package com.yeskery.nut.util;

import com.yeskery.nut.core.ErrorController;
import com.yeskery.nut.core.ProxyObjectInvokeException;
import com.yeskery.nut.core.RequestApplicationContext;
import com.yeskery.nut.core.ResponseNutException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;

/**
 * 异常工具类
 * @author sprout
 * @version 1.0
 * 2022-08-29 10:18
 */
public class ExceptionUtils {

    /**
     * 私有化构造方法
     */
    private ExceptionUtils() {
    }

    /**
     * 获取目标异常对象
     * @param e 原始异常对象
     * @return 目标异常对象
     */
    public static Exception getTargetException(Exception e) {
        Exception exception = e;
        while (true) {
            if (exception == null) {
                break;
            }
            if (exception instanceof ProxyObjectInvokeException) {
                Throwable cause = e.getCause();
                if (cause instanceof Exception) {
                    exception = (Exception) cause;
                }
            } else if (exception instanceof InvocationTargetException) {
                Throwable targetException = ((InvocationTargetException) exception).getTargetException();
                if (targetException instanceof Exception) {
                    exception = (Exception) targetException;
                }
            } else if (exception instanceof UndeclaredThrowableException) {
                Throwable undeclaredThrowable = ((UndeclaredThrowableException) exception).getUndeclaredThrowable();
                if (undeclaredThrowable instanceof InvocationTargetException) {
                    Throwable targetException = ((InvocationTargetException) undeclaredThrowable).getTargetException();
                    if (targetException instanceof Exception) {
                        exception = (Exception) targetException;
                    }
                }
            } else {
                break;
            }
        }

        return exception;
    }

    /**
     * 获取目标异常对象
     * @param throwable 原始异常对象
     * @return 目标异常对象
     */
    public static Throwable getTargetThrowable(Throwable throwable) {
        if (throwable instanceof ProxyObjectInvokeException) {
            return throwable.getCause();
        }
        if (throwable instanceof InvocationTargetException) {
            return  ((InvocationTargetException) throwable).getTargetException();
        } else if (throwable instanceof UndeclaredThrowableException) {
            Throwable undeclaredThrowable = ((UndeclaredThrowableException) throwable).getUndeclaredThrowable();
            if (undeclaredThrowable instanceof InvocationTargetException) {
                return  ((InvocationTargetException) undeclaredThrowable).getTargetException();
            }
        }
        return throwable;
    }

    /**
     * 获取{@link ResponseNutException}异常中的目标异常对象
     * @param e 原始异常对象
     * @return 目标异常对象
     */
    public static Throwable getResponseNutExceptionTargetThrowable(ResponseNutException e) {
        if (e == null) {
            return null;
        }
        Throwable throwable = e.getCause();
        if (throwable == null) {
            return null;
        }
        throwable = throwable.getCause();
        if (!(throwable instanceof InvocationTargetException)) {
            return null;
        }
        throwable = ((InvocationTargetException) throwable).getTargetException();
        if (throwable == null) {
            return null;
        }
        throwable = throwable.getCause();
        if (!(throwable instanceof InvocationTargetException)) {
            return null;
        }
        return ((InvocationTargetException) throwable).getTargetException();
    }

    /**
     * 获取{@link ResponseNutException}异常中的目标异常对象
     * @return 目标异常对象
     */
    public static Throwable getResponseNutExceptionTargetThrowable() {
        return getResponseNutExceptionTargetThrowable(RequestApplicationContext.getResource(
                ErrorController.REQUEST_EXCEPTION_HOLDER_KEY, ResponseNutException.class));
    }
}
